import tkMessageBox
from Tkinter import *
from shapes import *
from random import randint
from const  import *
from board  import *
from capteur import *
from math import sqrt

def level_thresholds( first_level, no_of_levels ):
    """
    Calculates the score at which the level will change, for n levels.
    """
    thresholds =[]
    for x in xrange( no_of_levels ):
        multiplier = 2**x
        thresholds.append( first_level * multiplier )
    
    return thresholds

class game_controller(object):
    """
    Main game loop and receives GUI callback events for keypresses etc...
    """

    def __init__(self, parent):
        """
        Intialise the game...
        """
        self.old_score = 0  #keeping the old score to test how many lines are made at a time
        self.parent = parent
        self.score = 0
        self.level = 0
        self.delay = 1000    #ms

        #lookup table
        self.shapes = [square_shape,
                      t_shape,
                      l_shape,
                      reverse_l_shape,
                      z_shape,
                      s_shape,
                      i_shape ]
        
        self.futur_shape = randint(0,len(self.shapes)-1)
        self.thresholds = level_thresholds( 500, NO_OF_LEVELS )
        self.futur_board = Futur(parent,scale=SCALE)
        self.status_bar = status_bar( parent )
        self.status_bar.pack(side=TOP,fill=X)
        #print "Status bar width",self.status_bar.cget("width")

        self.status_bar.set("Score: %-7d\t Level: %d " % (
            self.score, self.level+1)
        )
        
        self.board = Board(
            parent,
            scale=SCALE,
            max_x=MAXX,
            max_y=MAXY
            )
        
        self.board.pack(side=BOTTOM)
        
        self.parent.bind("<Left>", self.left_callback)
        self.parent.bind("<Right>", self.right_callback)
        self.parent.bind('<KeyPress-space>', self.up_callback)
        self.parent.bind("<Down>", self.down_callback)
        self.parent.bind("e", self.a_callback)
        self.parent.bind("r", self.s_callback)
        self.parent.bind("p", self.p_callback)
        
        self.shape = self.get_next_shape()
        #self.board.output()
        self.board_test = Board_test (self.board)
        self.lines_eff = Line_efficiency ()
        self.after_id = self.parent.after( self.delay, self.move_my_shape )
        self.keyboard_sensor = Keyboard_sensor ()
        
    def handle_move(self, direction):
        #if you can't move then you've hit something
        

        if not self.shape.move( direction ):
            # if your heading down then the shape has 'landed'
            if direction == DOWN:
                self.old_score = self.score
                self.score += self.board.check_for_complete_row(
                    self.shape.blocks
                    )
                self.run_tests()
                del self.shape
                self.shape = self.get_next_shape()
                
                # If the shape returned is None, then this indicates that
                # that the check before creating it failed and the
                # game is over!
                if self.shape is None:
                    tkMessageBox.showwarning(
                        title="GAME OVER",
                        message ="Score: %7d\tLevel: %d\t" % (
                            self.score, self.level),
                        parent=self.parent
                        )
                    del self.status_bar
                    del self.board
                    del self.shapes
                    self.parent.quit()
                    self.parent.destroy()
                    return None
                
                # do we go up a level?
                if (self.level < NO_OF_LEVELS and 
                    self.score >= self.thresholds[ self.level]):
                    self.level+=1
                    self.delay-=100
                    
                self.status_bar.set("Score: %-7d\t Level: %d " % (
                    self.score, self.level+1)
                )
                
                # Signal that the shape has 'landed'
                return False
        return True

    def left_callback( self, event ):
        self.keyboard_sensor.handle("left")
        if self.shape:
            self.handle_move( LEFT )
        
    def right_callback( self, event ):
        self.keyboard_sensor.handle("right")
        if self.shape:
            self.handle_move( RIGHT )

    def up_callback( self, event ):
        self.keyboard_sensor.handle("drop")
        if self.shape:
            # drop the tetrominoe to the bottom
            while self.handle_move( DOWN ):
                pass

    def down_callback( self, event ):
        self.keyboard_sensor.handle("down")
        if self.shape:
            self.handle_move( DOWN )
            
    def a_callback( self, event):
        self.keyboard_sensor.handle("rotate1")
        if self.shape:
            self.shape.rotate(clockwise=True)
            
    def s_callback( self, event):
        self.keyboard_sensor.handle("rotate2")
        if self.shape:
            self.shape.rotate(clockwise=False)
        
    def p_callback(self, event):
        self.parent.after_cancel( self.after_id )
        tkMessageBox.askquestion(
            title = "Paused!",
            message="Continue?",
            type=tkMessageBox.OK)
        self.after_id = self.parent.after( self.delay, self.move_my_shape )
    
    def move_my_shape( self ):
        if self.shape:
            self.handle_move( DOWN )
            self.after_id = self.parent.after( self.delay, self.move_my_shape )
        
    def get_next_shape( self ):
        """
        Randomly select which tetrominoe will be used next.
        """
        the_shape = self.shapes[ self.futur_shape ]
        self.futur_shape = randint(0,len(self.shapes)-1)
        self.futur_board.add_shape((self.shapes[ self.futur_shape]).check_and_create(self.futur_board)) ;
        return the_shape.check_and_create(self.board)


    def run_tests ( self ):
        self.lines_eff.run(int(sqrt((self.score - self.old_score)/100)))
        self.board_test.run(self.board)
        return 1


    def get_res (self ) :
        return self.board_test.get_res()+self.lines_eff.get_res()+self.keyboard_sensor.get_res()
    
